package com.dapengjiaoyu.polyv_video_plugin;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.RelativeLayout;

import com.easefun.polyvsdk.PolyvSDKClient;
import com.easefun.polyvsdk.live.PolyvLiveSDKClient;
import com.easefun.polyvsdk.live.chat.PolyvChatManager;
import com.easefun.polyvsdk.live.chat.PolyvChatMessage;
import com.easefun.polyvsdk.live.chat.api.PolyvChatHistory;
import com.easefun.polyvsdk.live.chat.api.listener.PolyvChatHistoryListener;
import com.easefun.polyvsdk.live.chat.playback.api.PolyvLive_Status;
import com.easefun.polyvsdk.live.chat.playback.api.listener.PolyvLive_StatusNorListener;
import com.easefun.polyvsdk.live.chat.util.NetUtil;
import com.easefun.polyvsdk.live.chat.util.NetUtilApiH1;
import com.easefun.polyvsdk.live.video.PolyvLiveVideoView;
import com.easefun.polyvsdk.live.video.PolyvLiveVideoViewListener;
import com.easefun.polyvsdk.live.video.PolyvLiveVideoViewListener.OnGestureClickListener;
import com.easefun.polyvsdk.sub.auxilliary.LogUtil;

import org.json.JSONArray;
import org.json.JSONObject;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.platform.PlatformView;
import io.socket.client.Socket;
import master.flame.danmaku.controller.DrawHandler;
import master.flame.danmaku.controller.IDanmakuView;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.DanmakuTimer;
import master.flame.danmaku.danmaku.model.IDanmakus;
import master.flame.danmaku.danmaku.model.IDisplayer;
import master.flame.danmaku.danmaku.model.android.DanmakuContext;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
import master.flame.danmaku.ui.widget.DanmakuView;

import static android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;

public class LiveVideoView implements PlatformView, MethodChannel.MethodCallHandler {
    private RelativeLayout layout;
    private PolyvLiveVideoView liveVideoView;
    private IDanmakuView danmakuView;
    private DanmakuContext mContext;
    private BaseDanmakuParser mParser;
    private PolyvChatManager chatManager;
    private PolyvChatHistory chatHistory;
    private final MethodChannel methodChannel;
    private final PluginRegistry.Registrar registrar;
    private final Context context;

    private String padding;
    private String textSize;
    private String textColor;

    private Map<String, Object> map;
    private HashMap<String, Object> message;
    private HashMap<String, Object> user;


    LiveVideoView(Context context, int viewId, Object args, PluginRegistry.Registrar registrar) {
        this.registrar = registrar;
        this.context = context;
        this.layout = getPolyvLiveVideoView(registrar, args);
        this.methodChannel = new MethodChannel(registrar.messenger(), "polyv_live_video_plugin_" + viewId);
        this.methodChannel.setMethodCallHandler(this);
        chatHistory = new PolyvChatHistory();
        if (chatManager == null) {
            chatManager = new PolyvChatManager();
        }
    }

    @Override
    public View getView() {
        return layout;
    }


    @Override
    public void dispose() {
        liveVideoView.destroy();
    }

    private RelativeLayout getPolyvLiveVideoView(PluginRegistry.Registrar registrar, Object args) {
        layout = (RelativeLayout) LayoutInflater.from(registrar.activity()).inflate(R.layout.polyv_live_video, null);
        liveVideoView = layout.findViewById(R.id.polyv_live_video_view);
        danmakuView = layout.findViewById(R.id.danmaku_view);
        liveVideoView.setNeedGestureDetector(true);
        liveVideoView.setOpenPreload(true);
        liveVideoView.setNeedGestureDetector(true);
        liveVideoView.setOnGestureClickListener(new OnGestureClickListener() {
            @Override
            public void callback(boolean start, boolean end) {
                Map<String, String> map = new HashMap<>();
                map.put("type", "click");
                methodChannel.invokeMethod("listener", map);
            }
        });
        liveVideoView.setOnGestureLeftDownListener(new PolyvLiveVideoViewListener.OnGestureLeftDownListener() {
            @Override
            public void callback(boolean b, boolean b1) {
                Map<String, Object> map = new HashMap<>();
                map.put("type", "leftDown");
                map.put("start", b);
                map.put("end", b1);
                methodChannel.invokeMethod("listener", map);
            }
        });

        liveVideoView.setOnGestureLeftUpListener(new PolyvLiveVideoViewListener.OnGestureLeftUpListener() {
            @Override
            public void callback(boolean b, boolean b1) {
                Map<String, Object> map = new HashMap<>();
                map.put("type", "leftUp");
                map.put("start", b);
                map.put("end", b1);
                methodChannel.invokeMethod("listener", map);
            }
        });

        liveVideoView.setOnGestureRightDownListener(new PolyvLiveVideoViewListener.OnGestureRightDownListener() {
            @Override
            public void callback(boolean b, boolean b1) {
                Map<String, Object> map = new HashMap<>();
                map.put("type", "rightDown");
                map.put("start", b);
                map.put("end", b1);
                methodChannel.invokeMethod("listener", map);
            }
        });

        liveVideoView.setOnGestureRightUpListener(new PolyvLiveVideoViewListener.OnGestureRightUpListener() {
            @Override
            public void callback(boolean b, boolean b1) {
                Map<String, Object> map = new HashMap<>();
                map.put("type", "rightUp");
                map.put("start", b);
                map.put("end", b1);
                methodChannel.invokeMethod("listener", map);
            }
        });

        liveVideoView.setOnGestureSwipeLeftListener(new PolyvLiveVideoViewListener.OnGestureSwipeLeftListener() {
            @Override
            public void callback(boolean b, boolean b1) {
                Map<String, Object> map = new HashMap<>();
                map.put("type", "swipeLeft");
                map.put("start", b);
                map.put("end", b1);
                methodChannel.invokeMethod("listener", map);
            }
        });

        liveVideoView.setOnGestureSwipeRightListener(new PolyvLiveVideoViewListener.OnGestureSwipeRightListener() {
            @Override
            public void callback(boolean b, boolean b1) {
                Map<String, Object> map = new HashMap<>();
                map.put("type", "swipeRight");
                map.put("start", b);
                map.put("end", b1);
                methodChannel.invokeMethod("listener", map);
            }
        });

        liveVideoView.setOnNoLiveAtPresentListener(new PolyvLiveVideoViewListener.OnNoLiveAtPresentListener() {
            @Override
            public void onNoLiveAtPresent() {
                Map<String, Object> map = new HashMap<>();
                map.put("type", "noLiveAtPresent");
                methodChannel.invokeMethod("listener", map);
            }
        });
        initDanmakuView();
        return layout;
    }

    private void initDanmakuView() {
        // -------------------仅对加载的弹幕有效-------------------//
        // 设置最大显示行数
        HashMap<Integer, Integer> maxLinesPair = new HashMap<Integer, Integer>();
        maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 2); // 滚动弹幕最大显示5行
        maxLinesPair.put(BaseDanmaku.TYPE_FIX_TOP, 2);
        maxLinesPair.put(BaseDanmaku.TYPE_FIX_BOTTOM, 2);
        // 设置是否禁止重叠
        HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<Integer, Boolean>();
        overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
        overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);
        overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_BOTTOM, true);
        // --------------------------------------------------------//

        mContext = DanmakuContext.create();
        mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 3).setDuplicateMergingEnabled(false)
                .setScrollSpeedFactor(1.2f).setScaleTextSize(1.2f).setTypeface(Typeface.SANS_SERIF)
                // .setCacheStuffer(new SpannedCacheStuffer(),
                // mCacheStufferAdapter) // 图文混排使用SpannedCacheStuffer
                .setMaximumLines(maxLinesPair).preventOverlapping(overlappingEnablePair);
        danmakuView.showFPS(false);
        danmakuView.enableDanmakuDrawingCache(false);
        danmakuView.setCallback(new DrawHandler.Callback() {
            @Override
            public void prepared() {
                danmakuView.start();
            }

            @Override
            public void updateTimer(DanmakuTimer timer) {
            }

            @Override
            public void danmakuShown(BaseDanmaku danmaku) {
            }

            @Override
            public void drawingFinished() {
            }
        });
        danmakuView.prepare(mParser = new BaseDanmakuParser() {
            @Override
            protected IDanmakus parse() {
                return new Danmakus();
            }
        }, mContext);
    }

    // 发送
    public void sendDanmaku(CharSequence message) {
        BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL, mContext);
        if (danmaku == null || danmakuView == null) {
            return;
        }
        danmaku.padding = padding != null ? Integer.parseInt(padding) : 5;
        danmaku.priority = 1; // 0:可能会被各种过滤器过滤并隐藏显示
        danmaku.isLive = true;
        danmaku.setTime(danmakuView.getCurrentTime() + 100);
        danmaku.textSize = textSize != null ? Integer.parseInt(textSize) : 18f;
        danmaku.textColor = textColor != null ? Color.parseColor(textColor) : Color.BLACK;
        danmaku.textShadowColor = Color.WHITE;
        danmaku.text = message;
        danmakuView.addDanmaku(danmaku);
    }

    @Override
    public void onMethodCall(final MethodCall methodCall, final MethodChannel.Result result) {
        Map<String, String> arg = (Map<String, String>) methodCall.arguments;
        switch (methodCall.method) {
            case "setVideoURI":
                liveVideoView.setVideoURI(Uri.parse(arg.get("url")));
                break;
            case "setLivePlay":
                liveVideoView.setLivePlay(arg.get("userId"), arg.get("channelId"), false);
                PolyvLive_Status status = new PolyvLive_Status();
                status.shutdownSchedule();
                status.getLive_Status(arg.get("channelId"), 6000, 4000, new PolyvLive_StatusNorListener() {
                    @Override
                    public void success(boolean isLiving, boolean isPPTLive) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("type", "liveStatus");
                        map.put("isLiving", isLiving);
                        map.put("isPPTLive", isPPTLive);
                        methodChannel.invokeMethod("listener", map);
                    }

                    @Override
                    public void fail(String s, int i) {

                    }
                });
                break;
            case "start":
                liveVideoView.start();
                break;
            case "resume":
                liveVideoView.resume();
                break;
            case "pause":
                liveVideoView.pause();
                break;
            case "stop":
                liveVideoView.stopPlayback();
                break;
            case "isPlaying":
                result.success(liveVideoView.isPlaying());
                break;
            case "destroy":
                liveVideoView.destroy();
                break;
            case "duration":
                result.success(liveVideoView.getDuration());
                break;
            case "currentPosition":
                result.success(liveVideoView.getCurrentPosition());
                break;
            case "bufferPercentage":
                result.success(liveVideoView.getBufferPercentage());
                break;
            case "brightness":
                result.success(liveVideoView.getBrightness());
                break;
            case "setBrightness":
                liveVideoView.setBrightness(registrar.activity(), Integer.parseInt(arg.get("brightness")));
                break;
            case "setVolume":
                liveVideoView.setVolume(Integer.parseInt(arg.get("volume")));
                break;
            case "volume":
                result.success(liveVideoView.getVolume());
                break;
            case "initDanMu":
                padding = arg.get("padding");
                textSize = arg.get("textSize");
                textColor = arg.get("textColor");
                break;
            case "sendDanMu":
                sendDanmaku(arg.get("message"));
                break;
            case "hideDanMu":
                danmakuView.hide();
                break;
            case "showDanMu":
                danmakuView.show();
                break;
            case "getChatUid":
                result.success(chatManager.getUid());
                break;
            case "getOnlineCount":
                result.success(chatManager.getOnlineCount());
                break;
            case "getChatHistory":
                chatHistory.getChatHistory(arg.get("channelId"), arg.get("userId"),
                        Integer.parseInt(arg.get("begin")), Integer.parseInt(arg.get("end")),
                        new PolyvChatHistoryListener() {
                            @Override
                            public void success(List<PolyvChatMessage> list) {
                                HashMap<String, Object> map = new HashMap<>();
                                map.put("status", "success");
                                map.put("data", list);
                                result.success(map);
                            }

                            @Override
                            public void fail(String failTips, int code) {
                                HashMap<String, Object> map = new HashMap<>();
                                map.put("status", "fail");
                                map.put("msg", failTips);
                                map.put("code", code);
                                result.success(map);
                            }
                        });
                break;
            case "setOnChatListener":
                if (chatManager == null) {
                    chatManager = new PolyvChatManager();
                }
                chatManager.setOnChatManagerListener(new PolyvChatManager.ChatManagerListener() {
                    @Override
                    public void connectStatus(PolyvChatManager.ConnectStatus connectStatus) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("type", "connect_status");
                        map.put("connectStatus", connectStatus.getDescribe());
                        methodChannel.invokeMethod("chatListener", map);
                    }

                    @Override
                    public void receiveChatMessage(PolyvChatMessage chatMessage) {
                        List<Map<String, Object>> list = new ArrayList<>();
                        map = new HashMap<>();
                        message = new HashMap<>();
                        user = new HashMap<>();
                        map.put("type", "receive_message");
                        message.put("chatType", chatMessage.getChatType());
                        message.put("value", chatMessage.getValues()[0]);
                        message.put("chatEvent", chatMessage.getEvent());
                        for (PolyvChatMessage.User user : chatMessage.banLists) {
                            Map<String, Object> banUser = new HashMap<>();
                            banUser.put("uid", user.getUid());
                            list.add(banUser);
                        }
                        message.put("banList", list);
                        user.put("nick", chatMessage.getUser().getNick());
                        user.put("uid", chatMessage.getUser().getUid());
                        message.put("user", user);

                        map.put("message", message);
                        methodChannel.invokeMethod("chatListener", map);
                    }
                });
                break;
            case "sendChatMsg":
                HashMap<String, Object> map = new HashMap<>();
                if (sendChatMessage(new PolyvChatMessage(arg.get("message")), arg.get("chapterId"), arg.get("courseId"))) {
                    map.put("status", "success");
                    map.put("msg", "发送成功");
                } else {
                    map.put("status", "fail");
                    map.put("msg", "连接聊天室异常,发送失败");
                }
                result.success(map);
                break;
            default:
                result.notImplemented();
        }
    }

    private boolean sendChatMessage(PolyvChatMessage chatMessage, String channelId, String courseId) {
        try {
            Field canSendChatMessageField = chatManager.getClass().getDeclaredField("canSendChatMessage");
            canSendChatMessageField.setAccessible(true);
            boolean canSendChatMessage = (boolean) canSendChatMessageField.get(chatManager);
            if (canSendChatMessage) {
                Field socketField = chatManager.getClass().getDeclaredField("socket");
                socketField.setAccessible(true);
                Socket socket = (Socket) socketField.get(chatManager);
                JSONObject jsonObject = new JSONObject();
                JSONArray jsonArray = new JSONArray();
                jsonObject.put("EVENT", "SPEAK");
                jsonArray.put(0, chatMessage.getValues()[0]);
                jsonObject.put("values", jsonArray);
                jsonObject.put("roomId", channelId);

                JSONObject sessionIdObj = new JSONObject();
                sessionIdObj.put("courseId", courseId);
                sessionIdObj.put("curriculumId", 1);
                jsonObject.put("sessionId", sessionIdObj);

                socket.emit("message", jsonObject.toString());
                chatMessage.setTime(System.currentTimeMillis());
                chatMessage.setSendSuccess(true);
                return true;
            }
        } catch (Throwable t) {
            return false;
        }
        return false;
    }
}